import types
from django.core import serializers
from datetime import datetime
from decimal import *
from django.core.serializers.json import DateTimeAwareJSONEncoder
from django.db import models
from django.template import loader
from django.utils import simplejson
from django.utils.encoding import force_unicode,smart_str,smart_unicode
from random import randint
from string import ascii_lowercase, digits

def json_encode(data, ensure_ascii=False, deep=3, ignore_fields=('user','members')):
    """
    The main issues with django's default json serializer is that properties that
    had been added to a object dynamically are being ignored (and it also has 
    problems with some models).
    """
    def _any(data, deep):
        ret = None
        if isinstance(data, list):
            ret = _list(data, deep)
        elif isinstance(data, dict):
            ret = _dict(data, deep)
        elif isinstance(data, Decimal):
            # json.dumps() cant handle Decimal
            ret = str(data)
        elif isinstance(data, models.query.QuerySet):
            # Actually its the same as a list ...
            ret = _list(data, deep)
        elif isinstance(data, models.Model):
            ret = _model(data, deep)
        else:
            try:
                ret = data.__unicode__()
            except:
                ret = data
        return ret

    def _model(data, deep):
	if deep == 1:
	    return _any(data.__dict__, deep)
	else:
	    ret = {}
	    for v in data._meta.fields:
		if not v.name in ignore_fields:
		    ret[v.name] = _any(getattr(data, v.name), deep-1)
	    for v in  data._meta.many_to_many:
		if not v.name in ignore_fields:
		    ret[v.name] = _any(getattr(data, v.name).all(), deep-1)
	    return ret

    def _list(data, deep):
        ret = []
        for v in data:
            ret.append(_any(v, deep))
        return ret

    def _dict(data, deep):
        ret = {}
        for k,v in data.items():
            ret[k] = _any(v, deep)
        return ret

    ret = _any(data, deep)

    return simplejson.dumps(ret, cls=DateTimeAwareJSONEncoder, ensure_ascii=ensure_ascii)
